﻿/// <reference path="../jquery-1.4.4.js" />
/// <reference path="../jquery-1.4.4-vsdoc.js" />

/*!  
** Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
** Dual licensed under the MIT and GPL licenses:
** http://www.opensource.org/licenses/mit-license.php
** http://www.gnu.org/licenses/gpl.html
** 
**----------------------------------------------------------------
** title        : DJME Grid
** version   : 2.0.2
** modified: 2010-2-22
** depends:
**    jquery.ui.core.js
**    jquery.ui.widget.js
**    jquery.ui.mouse.js
**    jquery.ui.draggable.js
**    jquery.ui.droppable.js
**    jquery.ui.sortable.js 
**    jquery.tmpl.js
**----------------------------------------------------------------
*/

(function ($) {
    $.widget("ui.dgrid", {
        options: {
            showScroll: false,
            sortable: true,
            groupable: true,
            sort: null,
            columnClick: null,
            selectedRow: null,
            rowSelected: null,
            addGroup: null,
            delGroup: null,
            filters: null,
            filterChanged: null
        },
        _create: function () {
            var self = this, el = this.element, eventPrefix = this.widgetEventPrefix;
            this.element.addClass("d-grid");

            this.header = $(".d-grid-header", el);
            this.footer = $(".d-grid-footer", el);
            this.columns = $(".d-grid-column", el);
            this.columnsArea = $(".d-grid-columns", el);
            this.dataArea = $(".d-grid-data-area", el);

            if (this.options.showScroll) {
                var h = this.element.height();
                this.element.addClass("d-grid-scrolling");
                self.columnsArea.css("overflow", "hidden");
                this.dataArea.height(h - this.header.height() - this.footer.height() - this.columnsArea.height() - 40)
                           .bind("scroll", function () {
                               self.columnsArea.scrollLeft(self.dataArea.scrollLeft());
                           });
            }

            if (this.options.filterChanged)
                this.element.bind(eventPrefix + "filterChanged", this.options.filterChanged);

            if (this.options.columnClick)
                this.element.bind(eventPrefix + "columnClick", this.options.columnClick);

            if (this.options.sort)
                this.element.bind(eventPrefix + "sort", this.options.sort);

            if (this.options.rowSelected)
                this.element.bind(eventPrefix + "rowSelected", this.options.rowSelected);

            if (this.options.addGroup)
                this.element.bind(eventPrefix + "addGroup", this.options.addGroup);

            if (this.options.delGroup)
                this.element.bind(eventPrefix + "delGroup", this.options.delGroup);

            this.columns.bind("click", function () {
                self._clearselection();
                $(this).addClass("d-grid-column-selected");
                var $cells = $("." + $(this).attr("id"), self.dataArea);
                $cells.addClass("d-grid-cell-selected");
                if (self.options.sortable) {
                    var _fieldName = $(this).find("input[type='hidden']");
                    var _asc = $(this).hasClass("d-grid-column-asc");

                    if ($(".d-grid-column-sorting-icon", this).length == 0) {
                        $("<span/>").addClass("d-grid-column-sorting-icon").appendTo($("a", this));
                        _asc = false;
                    }

                    if (_asc) {
                        $(this).removeClass("d-grid-column-asc");
                        $(this).addClass("d-grid-column-desc");
                        _asc = false;
                    }
                    else {
                        $(this).removeClass("d-grid-column-desc");
                        $(this).addClass("d-grid-column-asc");
                        _asc = true;
                    }

                    $(this).siblings().each(function (i, n) {
                        var $c = $(n),
                        $icon = $(".d-grid-column-sorting-icon", $c);

                        $c.removeClass("d-grid-column-desc")
                           .removeClass("d-grid-column-asc");

                        if ($icon.length) $icon.remove();
                    });

                    self._triggerEvent("sort", { field: _fieldName.val(), order: _asc ? "asc" : "desc" });
                }
                self._triggerEvent("columnClick", this);
            });

            this._initresizer();
            this._initrows();
            if (this.options.groupable)
                this._initgrouping();
            this._setColHeadersWidth();
        },
        _setColHeadersWidth: function () {
            //            var colTbl = $(">.d-grid-columns>table", this.element),
            //            datTbl = $(">d-grid-data-area>.d-grid-data-table", this.element);
            //            //if (datTbl.find(".d-grid-grouping-row").length == 0) {
            //                if (datTbl.children("colgroup").length) datTbl.children("colgroup").remove();
            //                datTbl.prepend(colTbl.children("colgroup").clone());
            //            //}
        },
        _initgrouping: function () {
            var self = this;
            $(".d-grid-groups", self.element).sortable({
                forceHelperSize: true,
                forcePlaceholderSize: true,
                placeholder: "ui-state-highlight"
            });

            $(".d-grid-groups", self.element).droppable({
                activeClass: "ui-state-active",
                hoverClass: "ui-state-highlight",
                over: function (event, ui) {
                    if (ui.helper.hasClass("d-grid-group-helper")) {
                        var _exists = $("." + ui.draggable.attr("id"), this);
                        if (_exists.length == 0)
                            ui.helper.addClass("d-grid-group-allowdrop");
                    }
                },
                out: function (event, ui) {
                    if (ui.helper.hasClass("d-grid-group-helper"))
                        ui.helper.removeClass("d-grid-group-allowdrop");
                },
                drop: function (event, ui) {
                    if (ui.helper.hasClass("d-grid-group-allowdrop")) {
                        var _emptyElement = $(".d-grid-group-empty", this);
                        if (_emptyElement.length) _emptyElement.hide();
                        var _gl = $("<li/>").addClass(ui.draggable.attr("id"))
                                                    .appendTo(this);
                        if (ui.draggable.hasClass("d-grid-column-asc"))
                            _gl.addClass("d-grid-column-asc");

                        if (ui.draggable.hasClass("d-grid-column-desc"))
                            _gl.addClass("d-grid-column-desc");

                        _gl.html(ui.draggable.html());
                        var $link = _gl.find("a");
                        $("<span/>").addClass("d-grid-group-remove-icon")
                                            .appendTo($link)
                                            .click(function () {
                                                _gl.remove();
                                                self.columnsArea.find(".d-grid-column:first").remove();
                                                if (self._getGroups().length == 0) {
                                                    _emptyElement = $(".d-grid-group-empty", $(".d-grid-groups", self.element));
                                                    if (_emptyElement.length) _emptyElement.show();
                                                }
                                                self._triggerEvent("delGroup", { groups: self._getGroups() });
                                            });

                        if ($link.find(".d-grid-column-sorting-icon").length == 0) {
                            _gl.addClass("d-grid-column-asc");
                            ui.draggable.addClass("d-grid-column-asc");
                            $("<span/>").addClass("d-grid-column-sorting-icon").appendTo($link);
                            $("<span/>").addClass("d-grid-column-sorting-icon").appendTo(ui.draggable.find("a"));
                        }

                        $link.click(function () {
                            ui.draggable.click();
                        });
                        $("<th/>").addClass("d-grid-column").prependTo(self.columnsArea.find(".d-grid-column:first").parent());
                        self._triggerEvent("addGroup", { groups: self._getGroups() });
                    }
                }
            });

            self.columns.draggable({
                appendTo: self.element,
                helper: function (event) {
                    return $("<div/>").addClass("d-grid-group-helper")
                                                .text($(this).text());
                },
                iframeFix: true
            });

            /*---------init added groups-----------*/
            var $addedGroups = $(".d-grid-groups", self.element).children("li:not(.d-grid-group-empty)");
            if ($addedGroups.length) {
                $addedGroups.each(function (i, n) {
                    $(n).find("a").click(function () {
                        var colName = $(this).siblings("input").val();
                        var colInstance = self._getColumn(colName);
                        colInstance.click();
                    });

                    $(n).find(".d-grid-group-remove-icon").click(function () {
                        $(n).remove();
                        self.columnsArea.find(".d-grid-column:first").remove();
                        if (self._getGroups().length == 0) {
                            _emptyElement = $(".d-grid-group-empty", $(".d-grid-groups", self.element));
                            if (_emptyElement.length) _emptyElement.show();
                        }
                        self._triggerEvent("delGroup", { groups: self._getGroups() });
                    });
                });
            }


        },
        _getColumn: function (colName) {
            var self = this;
            var result = null;
            self.columns.each(function (i, n) {
                var $hidden = $(n).find("input[type='hidden']");
                if ($hidden.length) {
                    if ($hidden.val() == colName) {
                        result = $(n);
                        return false;
                    }
                }
            });
            return result;
        },
        getGroups: function () {
            return this._getGroups();
        },
        _getGroups: function () {
            var _groups = [];
            $(".d-grid-groups", this.element).find("input").each(function (i, n) {
                $val = $(n);
                _groups.push($val.val());
            });
            return _groups;
        },
        _initresizer: function () {
            var self = this, resizHandler = function (event) {
                var $resizer = $(".d-grid-resizing", self.columnsArea);
                if ($resizer.length) {
                    var x = event.clientX;
                    $resizer.css("left", x + "px");
                    $(".d-grid-resize-helper", el).css("left", x + "px");

                    var targetCol = $resizer.data("column"),
                    _offsetX = x - $resizer.data("orgX"),
                    _nw = $resizer.data("orgWidth") + _offsetX;

                    targetCol.width(_nw + "px");

                    var relativeCols = $("." + targetCol.attr("id"), self.dataArea);
                    if (relativeCols.length)
                        relativeCols.width(_nw + "px");

                    var resizers = $resizer.siblings(".d-grid-resize-handler");
                    if (resizers.length) {
                        resizers.each(function (i, n) {
                            $(n).position({
                                my: "right top",
                                at: "right top",
                                of: $(n).data("column")
                            });
                        });
                    }
                }
            };

            var setSizeHandler = function (event) {
                var hResizing = $(".d-grid-resizing", self.columnsArea);
                if (hResizing.length) {
                    $(".d-grid-resize-helper", el).remove();
                    hResizing.removeClass("d-grid-resizing");
                }
            };

            //create column resizer
            self.columns.each(function (i, n) {
                var $col = $(n);
                if ($col.hasClass("d-grid-column-resizable")) {
                    var $rshandler = $("<div/>").addClass("d-grid-resize-handler").appendTo(self.columnsArea);

                    $rshandler.bind("mousedown", function () {
                        self._createResizeHelper($rshandler);
                        $rshandler.addClass("d-grid-resizing")
                                        .data("orgX", $rshandler.position().left)
                                        .data("orgWidth", $col.width());
                    })
                    .bind("mousemove", resizHandler)
                    .bind("mouseup", setSizeHandler)
                    .position({
                        my: "right top",
                        at: "right top",
                        of: $col
                    })
                    .data("column", $col);
                }
            });

            self.columnsArea.bind("mousemove", resizHandler)
                          .bind("mouseup", setSizeHandler);
        },
        _clearselection: function () {
            var selCells = $(".d-grid-cell-selected", this.dataArea);
            $(".d-grid-column", this.element).removeClass("d-grid-column-selected");
            if (selCells.length) selCells.removeClass("d-grid-cell-selected");
        },
        _triggerEvent: function (eventName, eventArgs) {
            this.element.trigger(this.widgetEventPrefix + eventName, eventArgs);
        },
        _initrows: function () {
            var $rows = $(".d-grid-row", this.dataArea), self = this;
            if ($rows.length) {

                $rows.click(function () {
                    self._clearselection();
                    $(".d-grid-cell", $(this)).addClass("d-grid-cell-selected");
                    self.options.selectedRow = this;
                    var _tmplItem = $(this).tmplItem(), _data = null;
                    if (_tmplItem)
                        _data = _tmplItem.data;

                    self._triggerEvent("rowSelected", { row: this, data: _data });
                });

                $rows.each(function (i, _r) {
                    if ((i % 2) != 0)
                        $(_r).addClass("d-grid-row-alt");
                });
            }

            /*-------------init group holder--------------------*/
            var $gHolder = self.dataArea.find(".d-grid-group-holder");
            $gHolder.each(function (i, n) {
                var $holder = $(n), parentRow = $holder.closest("tr"),
                 childrenRows = parentRow.nextUntil("tr[level='" + parentRow.attr("level") + "']"),
                 parentLevel = parseInt(parentRow.attr("level"));

                //if (childrenRows.length) {
                $holder.toggle(function () {
                    $(this).addClass("d-grid-group-collapse");

                    childrenRows.each(function (i, r) {
                        var rowLevel = parseInt($(r).attr("level"));
                        if (rowLevel > parentLevel)
                            $(r).hide();
                    });

                }, function () {
                    $(this).removeClass("d-grid-group-collapse");
                    childrenRows.each(function (i, r) {
                        var rowLevel = parseInt($(r).attr("level"));
                        if (rowLevel > parentLevel)
                            $(r).show();
                    });
                });
            });

            var $detailButtons = self.dataArea.find(".d-grid-detail-button");
            $detailButtons.each(function (i, n) {
                var dButton = $(n), nextDetailRow = $(n).closest(".d-grid-row").next(".d-grid-row-detail");

                dButton.click(function () {
                    if (!$(this).parent().hasClass("d-grid-detail-collapse")) {
                        $(this).parent().addClass("d-grid-detail-collapse");
                        if (nextDetailRow.length) { nextDetailRow.hide(); }
                    }
                    else {
                        if ($(this).children("a").length > 0) {
                            var _parent = $(this).parent(), _link = $(this).children("a"),
                            _loader = self._createLoader();
                            nextDetailRow.find(".d-grid-detail").load(_link.attr("href"), function () {
                                _parent.removeClass("d-grid-detail-collapse");
                                _link.remove();
                                _loader.remove();
                                if (nextDetailRow.length) { nextDetailRow.show(); }
                            });

                        } else {
                            $(this).parent().removeClass("d-grid-detail-collapse");
                            if (nextDetailRow.length) { nextDetailRow.show(); }
                        }
                    }
                });
            })
        },
        load: function (remoteUrl, routeData, tmplName, method, callback) {
            var self = this, $dataContainer = this.options.showScroll ? $(">.d-grid-data-area>table>tbody", this.element) : $(">table>.d-grid-data-area", this.element);
            var _loader = null;

            $.ajax({
                type: method,
                data: routeData,
                url: remoteUrl,
                dataType: "json",
                beforeSend: function () {
                    _loader = self._createLoader();
                },
                success: function (data) {
                    $dataContainer.empty();
                    $("#" + tmplName).tmpl(data.Model).appendTo($dataContainer);

                    if (self._getGroups().length)
                        self._reInitGroups();

                    self._initrows();
                    self._setColHeadersWidth();
                    if (_loader) _loader.remove();

                    if ($.isFunction(callback))
                        callback(data);
                }
            });
        },
        _reInitGroups: function () {
            var gCount = this._getGroups().length,
            colCount = this.columnsArea.find(".d-grid-column").length,
            dataRows = this.dataArea.find(".d-grid-row");

            for (var i = 0; i < gCount; i++) {
                var rows = this.dataArea.find(".d-grid-grouping-row[level='" + i.toString() + "']");
                var colspan = colCount - i;

                rows.each(function (_index, n) {
                    var $row = $(n);
                    var $gCell = $row.find(".d-grid-grouping-cell");
                    if ($gCell.length) {
                        if (colspan > 1) $gCell.attr("colspan", colspan.toString());

                        for (var j = 0; j < i; j++)
                            $("<td/>").addClass("d-grid-cell").prependTo($row);
                    }
                });

                dataRows.each(function (dataIndex, dataItem) {
                    $("<td/>").addClass("d-grid-cell").prependTo(dataItem);
                });
            }
            //this._initgrouping();
        },
        _createLoader: function () {
            var _loader = $("<div/>").addClass("d-big-loader").appendTo(this.element), _pos = this.dataArea.position();
            _loader.css({
                top: _pos.top + "px",
                left: _pos.left + "px",
                width: this.dataArea.width() + "px",
                height: this.dataArea.height() + "px"
            });
            return _loader;
        },
        _createResizeHelper: function ($handler) {
            var _helper = $("<div/>").addClass("d-grid-resize-helper").appendTo($(".d-grid-data-area", this.element));
            _helper.css({
                "left": $handler.position().left + "px",
                "height": $(".d-grid-data-area", this.element).height()
            });
            return _helper;
        },
        addFilter: function (_field, _operator, _term, _replaceExists) {
            if (this.options.filters == null) this.options.filters = [];
            if (_replaceExists) this._removeFilter(_field);
            var _formatTerm = _term;
            if (_operator == "startswith") { _formatTerm = "'" + _term + "%'"; }
            if (_operator == "endswith") { _formatTerm = "'%" + _term + "'"; }
            if (_operator == "contains") { _formatTerm = "'%" + _term + "%'"; }
            if (_operator == "not~contains") { _formatTerm = "'%" + _term + "%'"; }

            this.options.filters.push({ field: _field, operator: _operator, term: _formatTerm });
            this._triggerEvent("filterChanged", { filters: this.options.filters, value: this.getFilters() });
        },
        clearFilter: function () {
            this.options.filters = [];
        },
        removeFilter: function (_field) {
            this._removeFilter(_field);
            this._triggerEvent("filterChanged", { filters: this.options.filters, value: this.getFilters() });
        },
        _removeFilter: function (_field) {
            var tmpArgs = [];
            if (this.options.filters) {
                $.each(this.options.filters, function (i, n) {
                    if (n.field != _field)
                        tmpArgs.push(n);
                });

                this.options.filters = tmpArgs;
            }
        },
        setFilters: function (strFilters) {
            if (strFilters) {
                var fargs = strFilters.split("-"), tmpArgs = [];
                $.each(fargs, function (i, n) {
                    var exprArgs = n.split("~");
                    tmpArgs.push({
                        field: exprArgs[0],
                        operator: exprArgs[1],
                        term: exprArgs[2]
                    });
                });
                this.options.filters = tmpArgs;
            }
            else
                this.options.filters = [];
        },
        getFilters: function () {
            var strFilters = "", filterArgs = [];
            $.each(this.options.filters, function (i, n) {
                filterArgs.push(n.field + "~" + n.operator + "~" + n.term);
            });
            strFilters = filterArgs.join("-");
            return strFilters;
        },
        getOrders: function () {
            var strOrders = "", orderArgs = [];
            if (this.columns) {
                $.each(this.columns, function (i, n) {
                    var $col = $(n);
                    if ($col.hasClass("d-grid-column-asc"))
                        orderArgs.push($col.children("input[type='hidden']").val() + "~asc");
                    if ($col.hasClass("d-grid-column-desc"))
                        orderArgs.push($col.children("input[type='hidden']").val() + "~desc");
                });
            }
            strOrders = orderArgs.join("-");
            return strOrders;
        },
        _delegate: function (context, handler) {
            return function (e) {
                handler.apply(context, [e, this]);
            };
        },
        destroy: function () {
            $.Widget.prototype.destroy.call(this);
        }
    });
})(jQuery);
